"""
Note: Also see letterAvatar.jsx. Anything changed in this file (how colors are
      selected, the svg, etc) will also need to be changed there.
"""

from __future__ import annotations

from collections.abc import MutableMapping
from typing import IO
from urllib.parse import urlencode

from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.utils.encoding import force_str
from django.utils.html import escape, format_html
from django.utils.safestring import SafeString
from PIL import Image

from sentry.http import safe_urlopen
from sentry.utils.hashlib import sha256_text


def get_gravatar_url(
    email: str | None, size: int | None = None, default: int | str | None = "mm"
) -> str:
    if email is None:
        email = ""
    gravatar_url = "{}/avatar/{}".format(
        settings.SENTRY_GRAVATAR_BASE_URL,
        sha256_text(email.strip().lower()).hexdigest(),
    )

    properties: MutableMapping[str, int | str] = {}
    if size:
        properties["s"] = str(size)
    if default:
        properties["d"] = default
    if properties:
        gravatar_url += "?" + urlencode(properties)

    return gravatar_url


LETTER_AVATAR_COLORS = [
    "#4674ca",  # blue
    "#315cac",  # blue_dark
    "#57be8c",  # green
    "#3fa372",  # green_dark
    "#f9a66d",  # yellow_orange
    "#ec5e44",  # red
    "#e63717",  # red_dark
    "#f868bc",  # pink
    "#6c5fc7",  # purple
    "#4e3fb4",  # purple_dark
    "#57b1be",  # teal
    "#847a8c",  # gray
]

COLOR_COUNT = len(LETTER_AVATAR_COLORS)


def hash_user_identifier(identifier: str | int) -> int:
    identifier = force_str(identifier, errors="replace")
    return sum(map(ord, identifier))


def get_letter_avatar_color(identifier: str | int) -> str:
    hashed_id = hash_user_identifier(identifier)
    return LETTER_AVATAR_COLORS[hashed_id % COLOR_COUNT]


def get_letter_avatar(
    display_name: str | None,
    identifier: str | int,
    size: int | None = None,
    use_svg: bool | None = True,
    initials: str | None = None,
    rounded: bool | None = False,
) -> SafeString:
    display_name = (display_name or "").strip() or "?"
    names = display_name.split(" ")
    initials = initials or "{}{}".format(names[0][0], names[-1][0] if len(names) > 1 else "")
    initials = escape(initials.upper())
    color = get_letter_avatar_color(identifier)
    if use_svg:
        size_attrs = f'height="{size}" width="{size}"' if size else ""
        return format_html(
            '<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg" {size_attrs}>'
            '<rect x="0" y="0" width="120" height="120" rx="15" ry="15" fill={color}></rect>'
            '<text x="50%" y="50%" font-size="65" dominant-baseline="central" text-anchor="middle" fill="#FFFFFF">'
            "{initials}"
            "</text>"
            "</svg>",
            color=color,
            initials=initials,
            size_attrs=size_attrs,
        )
    else:
        size_attrs = f"height:{size}px;width:{size}px;" if size else ""
        font_size = "font-size:%spx;" % (size / 2) if size else ""
        line_height = "line-height:%spx;" % size if size else ""
        span_class = " rounded" if rounded else ""
        return format_html(
            '<span class="html-avatar{span_class}" '
            'style="background-color:{color};{size_attrs}{font_size}{line_height}">'
            "{initials}</span>",
            color=color,
            initials=initials,
            size_attrs=size_attrs,
            font_size=font_size,
            line_height=line_height,
            span_class=span_class,
        )


def get_email_avatar(
    display_name: str | None,
    identifier: str,
    size: int | None = None,
    try_gravatar: bool | None = True,
) -> SafeString:
    if try_gravatar:
        try:
            validate_email(identifier)
        except ValidationError:
            pass
        else:
            try:
                resp = safe_urlopen(get_gravatar_url(identifier, default=404))
            except Exception:
                pass
            else:
                if resp.status_code == 200:
                    # default to mm if including in emails
                    gravatar_url = get_gravatar_url(identifier, size=size)
                    return format_html('<img class="avatar" src="{}">', gravatar_url)
    return get_letter_avatar(display_name, identifier, size, use_svg=False)


def get_platform_avatar(
    display_name: str | None,
    size: int | None = None,
) -> SafeString:
    # TODO: @taylangocmen add platformicons from package when available
    return format_html(
        '<img class="avatar" src="https://raw.githubusercontent.com/getsentry/platformicons/master/svg/{display_name}.svg" height={size}>',
        display_name=display_name,
        size=size,
    )


def is_black_alpha_only(data: IO[bytes]) -> bool:
    """Check if an image has only black pixels (with alpha)"""
    result = False
    with Image.open(data) as image:
        if image.mode == "RGBA":
            result = not any(p[:3] != (0, 0, 0) for p in list(image.getdata()))
    data.seek(0)
    return result
